package repo

import (
	"git.multiverse.io/eventkit/dxc-server/mgmt/redundancy_abnormal_txn"
	"git.multiverse.io/eventkit/dxc-server/models"
	"git.multiverse.io/framework/log"
)

type HybridStorage struct {
	redundancyRepository Repository
	memoryRepository     Repository
}

func NewHybridStorage(repositoryType string) *HybridStorage {
	log.Infos("Start initialize hybrid storage...")
	defer log.Infos("Successfully initialized hybrid storage!")
	var redundancyRepository Repository
	switch repositoryType {
	case Hybrid_With_Redis_Storage:
		redundancyRepository = NewRedisRepository()
	case Hybrid_With_Hazelcast_Storage:
		redundancyRepository = NewHazelcastRepository()
	}
	return &HybridStorage{
		redundancyRepository: redundancyRepository,
		memoryRepository:     NewMemoryTxnRepository(),
	}
}

func (h *HybridStorage) GetRedundancyRepo() Repository {
	return h.redundancyRepository
}

func (h *HybridStorage) GetMemoryRepo() Repository {
	return h.memoryRepository
}

func (h *HybridStorage) AddRoot(transaction *models.Transaction) (int, error) {
	count, err := h.memoryRepository.AddRoot(transaction)
	if err != nil {
		return 0, err
	}
	_, err = h.redundancyRepository.AddRoot(transaction)
	if err != nil {
		log.Warnsf("[Remote cache]Add root information failed, error=%++v", err)
		redundancy_abnormal_txn.ReportRedundancyAbnormalTransactionToDtsMgmt(nil, transaction.RootXid, "AddRoot", transaction)
	}
	return count, nil
}

func (h *HybridStorage) AddBranch(transaction *models.Transaction) (int, error) {
	count, err := h.memoryRepository.AddBranch(transaction)
	if err != nil {
		return 0, err
	}
	_, err = h.redundancyRepository.AddBranch(transaction)
	if err != nil {
		log.Warnsf("[Remote cache]Add branch information failed, error=%++v", err)
		rootTransaction, _ := h.memoryRepository.FindAllBranchByRootXid(transaction.RootXid)
		redundancy_abnormal_txn.ReportRedundancyAbnormalTransactionToDtsMgmt(rootTransaction, transaction.RootXid, "AddBranch", transaction)
	}
	return count, nil
}

func (h *HybridStorage) FindAllBranchByRootXid(rootXid string) (*models.RootTransaction, error) {
	return h.memoryRepository.FindAllBranchByRootXid(rootXid)
}

func (h *HybridStorage) DeleteTxn(rootXid string) (int, error) {
	count, err := h.memoryRepository.DeleteTxn(rootXid)
	if err != nil {
		return 0, err
	}
	_, err = h.redundancyRepository.DeleteTxn(rootXid)
	if err != nil {
		log.Warnsf("[Remote cache]Delete transaction failed, error=%++v", err)
		rootTransaction, _ := h.memoryRepository.FindAllBranchByRootXid(rootXid)
		redundancy_abnormal_txn.ReportRedundancyAbnormalTransactionToDtsMgmt(rootTransaction, rootXid, "DeleteTxn", rootXid)
	}
	return count, nil
}

func (h *HybridStorage) IsExistsRootTransaction(rootXid string) (bool, error) {
	return h.memoryRepository.IsExistsRootTransaction(rootXid)
}

func (h *HybridStorage) TryCallback(rootXid string, callbackType string) (*models.RootTransaction, error) {
	result, err := h.memoryRepository.TryCallback(rootXid, callbackType)
	if err != nil {
		return nil, err
	}
	_, err = h.redundancyRepository.TryCallback(rootXid, callbackType)
	if err != nil {
		log.Warnsf("[Remote cache]Try callback failed, error=%++v", err)
		rootTransaction, _ := h.memoryRepository.FindAllBranchByRootXid(rootXid)
		redundancy_abnormal_txn.ReportRedundancyAbnormalTransactionToDtsMgmt(rootTransaction, rootXid, "TryCallback", rootXid, callbackType)
	}
	return result, nil
}

func (h *HybridStorage) TryEnList(rootXid string) error {
	return h.memoryRepository.TryEnList(rootXid)
}

func (h *HybridStorage) Recovery(root *models.RootTransaction) (int, error) {
	return h.memoryRepository.Recovery(root)
}

func (h *HybridStorage) IsExistsBranchTransaction(rootXid string, branchXid string) (bool, error) {
	return h.memoryRepository.IsExistsBranchTransaction(rootXid, branchXid)
}

func (h *HybridStorage) CallbackFail(rootXid string, branches []*models.Transaction, firstTimeCallback bool) (int, error) {
	result, err := h.memoryRepository.CallbackFail(rootXid, branches, firstTimeCallback)
	if err != nil {
		return 0, err
	}
	_, err = h.redundancyRepository.CallbackFail(rootXid, branches, firstTimeCallback)
	if err != nil {
		log.Errorsf("[Remote cache]Callback failed, error=%++v", err)
	}
	return result, nil
}

func (h *HybridStorage) FindRootBranchesByTimeExpire(expireSeconds int64) (rootXIds []*models.Transaction, err error) {
	return h.memoryRepository.FindRootBranchesByTimeExpire(expireSeconds)
}

func (h *HybridStorage) UpdateBranchTryFailedIgnoreCallbackCancel(rootXid string, branchXid string) (int, error) {
	result, err := h.memoryRepository.UpdateBranchTryFailedIgnoreCallbackCancel(rootXid, branchXid)
	if err != nil {
		return 0, err
	}
	_, err = h.redundancyRepository.UpdateBranchTryFailedIgnoreCallbackCancel(rootXid, branchXid)
	if err != nil {
		log.Errorsf("[Remote cache]Callback failed, error=%++v", err)
	}
	return result, nil
}

func (h *HybridStorage) ExpireTime(rootXid string) (int, error) {
	count, err := h.memoryRepository.ExpireTime(rootXid)
	if err != nil {
		return count, err
	}
	_, err = h.redundancyRepository.ExpireTime(rootXid)
	if err != nil {
		log.Errorsf("[Remote cache]ExpireTime failed, error=%++v", err)
	}
	return count, err
}

func (h *HybridStorage) LoadRootsFromPersistenceRepo(count int64) ([]string, error) {
	return h.redundancyRepository.LoadRootsFromPersistenceRepo(count)
}
